package model

import (
	"database/sql"
	"errors"
	"github.com/astaxie/beego"
	"math"
	"mime/multipart"
	"nspel/entity"
	"nspel/util"
	"strconv"
	"time"
)

type PostPhysicalImportSubmit struct {
	ImportFile  multipart.File
	MeasureDate time.Time
	SchoolId    int64
}

func (postPhysicalImportSubmit *PostPhysicalImportSubmit) Validate(c *beego.Controller) (*entity.School, error) {
	file, fileHeader, err := c.GetFile("import")
	if err != nil {
		return nil, err
	}
	if !util.ValidateFileType(fileHeader, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") {
		return nil, errors.New("只支持xlsx文件")
	}
	measureData, err := time.Parse("2006-01-02", c.GetString("measureDate"))
	if err != nil {
		return nil, err
	}
	measureData = measureData.Local()
	schoolId, err := c.GetInt64("schoolId")
	if err != nil {
		return nil, err
	}
	school := new(entity.School)
	err = school.SelectAllById(schoolId)
	if err != nil {
		return nil, err
	}
	postPhysicalImportSubmit.ImportFile = file
	postPhysicalImportSubmit.MeasureDate = measureData
	postPhysicalImportSubmit.SchoolId = schoolId
	return school, nil
}

type PhysicalInfo struct {
	Date          string    `json:"date"`
	Temperature   [2]string `json:"temperature"`
	Weather       string    `json:"weather"`
	WindDirection string    `json:"windDirection"`
	WindLevel     string    `json:"windLevel"`
	Air           string    `json:"air"`
}

type GetPhysicalListReq struct {
	ProvinceId   int64
	CityId       int64
	AreaId       int64
	SchoolName   string
	JoinYear     int64
	SchoolRollId string
	PageSize     int64
	CurrentPage  int64
}

func (getPhysicalListReq *GetPhysicalListReq) Validate(provinceId string, cityId string, areaId string, schoolName string, joinYear string, schoolRollId string, pageSize string, currentPage string, c *beego.Controller) bool {
	var err error
	getPhysicalListReq.ProvinceId, err = c.GetInt64(provinceId)
	if err != nil {
		return false
	}
	getPhysicalListReq.CityId, err = c.GetInt64(cityId)
	if err != nil {
		return false
	}
	getPhysicalListReq.AreaId, err = c.GetInt64(areaId)
	if err != nil {
		return false
	}
	getPhysicalListReq.SchoolName = c.GetString(schoolName)
	getPhysicalListReq.JoinYear, err = c.GetInt64(joinYear)
	if err != nil {
		return false
	}
	getPhysicalListReq.SchoolRollId = c.GetString(schoolRollId)
	getPhysicalListReq.PageSize, err = c.GetInt64(pageSize)
	if err != nil {
		return false
	}
	getPhysicalListReq.CurrentPage, err = c.GetInt64(currentPage)
	if err != nil {
		return false
	}
	return true
}

type PostPhysicalModifyReq struct {
	Id                    int64     `json:"id"`
	GradeYear             int64     `json:"gradeYear"`
	Grade                 int64     `json:"grade"`
	Class                 int64     `json:"class"`
	MeasureDate           time.Time `json:"measureDate"`
	IsExemption           string    `json:"isExemption"`
	Height                string    `json:"height"`
	Weight                string    `json:"weight"`
	VitalCapacity         string    `json:"vitalCapacity"`
	FiftyMeters           string    `json:"fiftyMeters"`
	SitAndReach           string    `json:"sitAndReach"`
	OneMinuteRopeSkipping string    `json:"oneMinuteRopeSkipping"`
	OneMinuteSitUps       string    `json:"oneMinuteSitUps"`
	ShuttleRun            string    `json:"shuttleRun"`
	StandingLongJump      string    `json:"standingLongJump"`
	Chinning              string    `json:"chinning"`
	OneThousandMeters     string    `json:"oneThousandMeters"`
	EightHundredMeters    string    `json:"eightHundredMeters"`
	BodyFat               string    `json:"bodyFat"`
	Grip                  string    `json:"grip"`
	ResponseCapability    string    `json:"responseCapability"`
	BalanceAbility        string    `json:"balanceAbility"`
	VerticalJump          string    `json:"verticalJump"`
}

func (postPhysicalModifyReq *PostPhysicalModifyReq) Validate() (bool, error, *entity.Score) {
	score := new(entity.Score)
	err := score.SelectAllById(postPhysicalModifyReq.Id)
	if err != nil {
		return false, err, nil
	}
	if postPhysicalModifyReq.GradeYear < 2000 || int(postPhysicalModifyReq.GradeYear) > time.Now().Year() {
		return false, nil, nil
	}
	school := new(entity.School)
	err = school.SelectAllById(score.SchoolId)
	if err != nil {
		return false, err, nil
	}
	if entity.SchoolTypeMapCode[school.SchoolType] == "小" {
		if postPhysicalModifyReq.Grade != 11 && postPhysicalModifyReq.Grade != 12 && postPhysicalModifyReq.Grade != 13 && postPhysicalModifyReq.Grade != 14 && postPhysicalModifyReq.Grade != 15 && postPhysicalModifyReq.Grade != 16 {
			return false, nil, nil
		}
	} else if entity.SchoolTypeMapCode[school.SchoolType] == "初" {
		if postPhysicalModifyReq.Grade != 21 && postPhysicalModifyReq.Grade != 22 && postPhysicalModifyReq.Grade != 23 {
			return false, nil, nil
		}
	} else if entity.SchoolTypeMapCode[school.SchoolType] == "高" {
		if postPhysicalModifyReq.Grade != 31 && postPhysicalModifyReq.Grade != 32 && postPhysicalModifyReq.Grade != 33 {
			return false, nil, nil
		}
	}
	if postPhysicalModifyReq.Class <= 0 || postPhysicalModifyReq.Class > 99 {
		return false, nil, nil
	}
	score.Grade = strconv.FormatInt(postPhysicalModifyReq.Grade, 10)
	class := strconv.FormatInt(postPhysicalModifyReq.Class, 10)
	if len(class) == 1 {
		class = "0" + class
	}
	score.Class = strconv.FormatInt(postPhysicalModifyReq.GradeYear, 10) + strconv.FormatInt(postPhysicalModifyReq.Grade, 10)[0:1] + class
	score.MeasurementDate = postPhysicalModifyReq.MeasureDate
	if postPhysicalModifyReq.IsExemption == "是" {
		score.IsExemption = true
	} else if postPhysicalModifyReq.IsExemption == "否" {
		score.IsExemption = false
	}
	var ok bool
	score.Height, ok = validateNullFloat64(&postPhysicalModifyReq.Height, 50, 300, false, -1000)
	if !ok {
		return false, nil, nil
	}
	score.Weight, ok = validateNullFloat64(&postPhysicalModifyReq.Weight, 10, 1000, false, -1000)
	if !ok {
		return false, nil, nil
	}
	score.VitalCapacity, ok = validateNullFloat64(&postPhysicalModifyReq.VitalCapacity, 0, 20000, false, -1000)
	if !ok {
		return false, nil, nil
	}
	score.FiftyMeters, ok = validateNullFloat64(&postPhysicalModifyReq.FiftyMeters, 5, 100, false, -1000)
	if !ok {
		return false, nil, nil
	}
	score.SitAndReach, ok = validateNullFloat64(&postPhysicalModifyReq.SitAndReach, -100, 100, false, -1000)
	if !ok {
		return false, nil, nil
	}
	score.ShuttleRun, ok = validateNullFloat64(&postPhysicalModifyReq.ShuttleRun, 40, 600, false, -1000)
	if !ok {
		return false, nil, nil
	}
	score.OneMinuteSitUp, ok = validateNullFloat64(&postPhysicalModifyReq.OneMinuteSitUps, 0, 100, false, -1000)
	if !ok {
		return false, nil, nil
	}
	score.OneMinuteRopeSkipping, ok = validateNullFloat64(&postPhysicalModifyReq.OneMinuteRopeSkipping, 0, 300, false, -1000)
	if !ok {
		return false, nil, nil
	}
	score.StandingLongJump, ok = validateNullFloat64(&postPhysicalModifyReq.StandingLongJump, 0, 400, false, -1000)
	if !ok {
		return false, nil, nil
	}
	score.EightHundredMeters, ok = validateNullFloat64(&postPhysicalModifyReq.EightHundredMeters, 120, 1800, false, -1000)
	if !ok {
		return false, nil, nil
	}
	score.OneThousandMeters, ok = validateNullFloat64(&postPhysicalModifyReq.OneThousandMeters, 120, 1800, false, -1000)
	if !ok {
		return false, nil, nil
	}
	score.Chinning, ok = validateNullFloat64(&postPhysicalModifyReq.Chinning, 0, 100, false, -1000)
	if !ok {
		return false, nil, nil
	}
	score.BodyFat, ok = validateNullFloat64(&postPhysicalModifyReq.BodyFat, 0, 100, false, -1000)
	if !ok {
		return false, nil, nil
	}
	score.GripStrength, ok = validateNullFloat64(&postPhysicalModifyReq.Grip, 0, 100, false, -1000)
	if !ok {
		return false, nil, nil
	}
	score.ResponseCapability, ok = validateNullFloat64(&postPhysicalModifyReq.ResponseCapability, 0, 10, false, -1000)
	if !ok {
		return false, nil, nil
	}
	score.BalanceAbility, ok = validateNullFloat64(&postPhysicalModifyReq.BalanceAbility, 0, 100, false, -1000)
	if !ok {
		return false, nil, nil
	}
	score.VerticalJump, ok = validateNullFloat64(&postPhysicalModifyReq.VerticalJump, 0, 100, false, -1000)
	if !ok {
		return false, nil, nil
	}
	if score.Height.Valid && score.Weight.Valid {
		score.BodyMassIndex.Valid = true
		score.BodyMassIndex.Float64 = score.Weight.Float64 / math.Pow(score.Height.Float64/100, 2)
	} else {
		score.BodyMassIndex.Valid = false
	}
	score.MissingTestNum = 0
	score.PhysicalBasicScore.Float64 = 0
	score.PhysicalExtraScore.Float64 = 0
	score.PhysicalTotalScore.Float64 = 0
	util.CalculatePhysicalScore(score)
	return true, nil, score
}

func validateNullFloat64(source *string, minFloat64 float64, maxFloat64 float64, isRequire bool, defaultValue float64) (nullFloat64 sql.NullFloat64, ok bool) {
	nullFloat64.Float64, ok = validateFloat64(source, minFloat64, maxFloat64, isRequire, defaultValue)
	if len(*source) != 0 {
		nullFloat64.Valid = true
	}
	return
}

func validateFloat64(source *string, minFloat64 float64, maxFloat64 float64, isRequire bool, defaultValue float64) (float64, bool) {
	if len(*source) == 0 {
		if isRequire {
			return defaultValue, false
		} else {
			return defaultValue, true
		}
	} else {
		value, err := strconv.ParseFloat(*source, 64)
		if err != nil {
			return defaultValue, false
		} else {
			if value > maxFloat64 {
				return defaultValue, false
			} else if value < minFloat64 {
				return defaultValue, false
			}
		}
		return value, true
	}
}

type GetPhysicalExportReq struct {
	ProvinceId   int64
	CityId       int64
	AreaId       int64
	SchoolName   string
	JoinYear     int64
	SchoolRollId string
}

func (getPhysicalExportReq *GetPhysicalExportReq) Validate(provinceId string, cityId string, areaId string, schoolName string, joinYear string, schoolRollId string, c *beego.Controller) bool {
	var err error
	getPhysicalExportReq.ProvinceId, err = c.GetInt64(provinceId)
	if err != nil {
		return false
	}
	getPhysicalExportReq.CityId, err = c.GetInt64(cityId)
	if err != nil {
		return false
	}
	getPhysicalExportReq.AreaId, err = c.GetInt64(areaId)
	if err != nil {
		return false
	}
	getPhysicalExportReq.SchoolName = c.GetString(schoolName)
	getPhysicalExportReq.JoinYear, err = c.GetInt64(joinYear)
	if err != nil {
		return false
	}
	getPhysicalExportReq.SchoolRollId = c.GetString(schoolRollId)
	return true
}
